<?php

namespace App\Models\AppHome\AuthManage;

use App\Facades\ScarecrowDoLog;
use App\Models\User;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;

class LoginModel
{
	//用户密码盐值
	protected static $key = "ScarecrowAuthKey";

	//用户Cache缓存KEY前缀
	protected static $cachePrefix = "SET_APP_USER_INFO_";

	//缓存失效时间 S
	protected static $expireTime = 86400;

	//默认API调用次数
	public static $callNum = 20000;

	//设置请求来源 2:AppHome
	public static $src = 2;

    /**
     * 创建用户的存储密码
     * @param $userPassword 用户实名密码
     * @return array
     */
    public static function createCheckPassword($userPassword) {
        return ModelReturn(RETURN_SUCCESS, '', md5(self::$key . $userPassword . self::$key));
    }

	/**
	 * 登录用户
	 * @param $userName 用户登录名
	 * @param $userPassword 用户密码
	 * @return array
	 * @throws \Exception
	 */
	public static function LoginUser($userName, $userPassword)
	{
		$userObj = DB::table('sc_user')->where(['username' => $userName])->first();
		if (!$userObj) {
			return ModelReturn(RETURN_FAIL, '用户名或密码错误');
		}
		$userObj = DbObjectToArr($userObj);
		$checkPassword = self::createCheckPassword($userPassword)['data'];

		if ($checkPassword !== $userObj['password']) {
			return ModelReturn(RETURN_FAIL, '用户名或密码错误');
		}

		$tokenInfo = CreateToken($userObj['id']);
		$cacheToken = self::$cachePrefix . $tokenInfo['token'];
		unset($userObj['password']);

		$nowTime = time();
		$expireTime = $nowTime + self::$expireTime;
		$cacheData = [
			'uid'	=>	$userObj['id'],
			'token'	=>	$tokenInfo['token'],
			'expire_time'	=>	$expireTime,
			'update_time'	=>	$nowTime,
			'call_num'		=>	self::$callNum,
			'is_invalid'	=>	0,
            'src'           =>  self::$src,
            'login_time'    =>  $nowTime
		];

		$userObj['tokenInfo'] = $cacheData;
		//如果需要路由权限，则在此处进行绑定
		$userObj['authList'] = self::getUserAuthList($userObj['id']);
		try {
		    Db::beginTransaction();
			$oldToken = DB::table('sc_token_cache')->whereRaw("uid=? AND src=?", [$userObj['id'], self::$src])->first();
            $oldToken = DbObjectToArr($oldToken);
			if ($oldToken) {
                Cache::forget(self::$cachePrefix . $oldToken['token']);
                DB::table('sc_token_cache')->whereRaw("uid=? AND src=?", [$userObj['id'], self::$src])->update($cacheData);
            } else {
                DB::table('sc_token_cache')->insert($cacheData);
            }
            Cache::put($cacheToken, $userObj, self::$expireTime);
			defined('APP_USER_TOKE_SRC') or define('APP_USER_TOKE_SRC', self::$src);
			HandleLog()->addLog('u', ['username' => $userName], '登录了系统', $cacheData['token']);
            if (env("APP_ENV") !== "testing") {
                $cacheData['token'] = $tokenInfo['cryptToken'];
            } else {
                $cacheData['cryptToken'] = $tokenInfo['cryptToken'];
            }
			Db::commit();
			return ModelReturn(RETURN_SUCCESS, '登录成功', $cacheData);
		} catch (\Throwable $e) {
		    DB::rollBack();
			if (config('app.debug')) {
				return ModelReturn($e->getCode(), $e->getMessage());
			} else {
				return ModelReturn($e->getCode(), "登录失败");
			}
		}
	}

	/**
	 * 获取用户路由权限列表
	 * @param $uid 用户ID
	 * @return array
	 */
	protected static function getUserAuthList($uid)
	{
		$authList = [
			//			'/api/login_out'
		];
		return $authList;
	}

	/**
     * 获取用户信息
	 * @param $token 用户TOKEN
	 * @param String $key 获取的KEY
	 * @param string $default 默认值
	 * @param bool $mustDb 是否强制从DB中获取
	 * @return array
	 */
	public static function getUserInfo($token, $key = '', $default = "", $mustDb = false)
	{
		$cacheToken = self::$cachePrefix . $token;
		if (!$mustDb && Cache::has($cacheToken)) {
			$userInfo = Cache::get($cacheToken);
			if ($userInfo) {
				if ($key) {
					$keyList = explode('.', $key);
					$keyList = array_filter($keyList);
					$tempData = $userInfo;
					foreach ($keyList as $item) {
						if (isset($tempData[$item])) {
							$tempData = $tempData[$item];
						} else {
							return ModelReturn(RETURN_SUCCESS, '获取成功', $default);
						}
					}
					return ModelReturn(RETURN_SUCCESS, '获取成功', $tempData);
				} else {
					return ModelReturn(RETURN_SUCCESS, '获取成功', $userInfo);
				}
			}
		}

		$nowTime = time();
		$userObj = DB::table('sc_token_cache as t1')->leftJoin('sc_user as t2', 't2.id', '=', 't1.uid')->whereRaw("t1.expire_time>{$nowTime} AND t1.call_num>0 AND t1.token=? AND t1.is_invalid=0 AND t1.src=?", [$token, self::$src])->select(['t2.*', 't1.uid', 't1.token', 't1.expire_time', 't1.update_time', 't1.call_num', 't1.is_invalid'])->first();
		if (!$userObj) {
			return ModelReturn(RETURN_CHECK_DATA_DB_FAIL, '用户不存在');
		}
		$userObj = DbObjectToArr($userObj);
		unset($userObj['password']);

		$tokenInfo = [
			'uid'	=>	$userObj['uid'],
			'token'	=>	$userObj['token'],
			'expire_time'	=>	$userObj['expire_time'],
			'update_time'	=>	time(),
			'call_num'		=>	$userObj['call_num'],
			'is_invalid'	=>	$userObj['is_invalid']
		];

		$userObj['tokenInfo'] = $tokenInfo;
		//如果需要路由权限，则在此处进行绑定
		$userObj['authList'] = self::getUserAuthList($userObj['id']);
		Cache::put($cacheToken, $userObj, self::$expireTime);

		$userInfo = $userObj;
		if ($userInfo) {
			if ($key) {
				$keyList = explode('.', $key);
				$keyList = array_filter($keyList);
				$tempData = $userInfo;
				foreach ($keyList as $item) {
					if (isset($tempData[$item])) {
						$tempData = $tempData[$item];
					} else {
						return ModelReturn(RETURN_SUCCESS, '获取成功', $default);
					}
				}
				return ModelReturn(RETURN_SUCCESS, '获取成功', $tempData);
			}
		}

		return ModelReturn(RETURN_SUCCESS, '获取成功', $userObj);
	}

	/**
	 * 更新token
	 * @param $token 用户TOKEN
	 * @return array
	 * @throws \Exception
	 */
	public static function updateToken($token)
	{
		$userInfo = self::getUserInfo($token);
		if ($userInfo['code'] !== RETURN_SUCCESS) {
			return $userInfo;
		}

		$userObj = $userInfo['data'];
		$newTokenInfo = CreateToken($userObj['id']);
		$expireTime = time() + self::$expireTime;
		$updateTokenInfo = [
			'token'	=>	$newTokenInfo['token'],
			'expire_time'	=>	$expireTime,
			'update_time'	=>	time(),
			'call_num'		=>	self::$callNum,
			'is_invalid'	=>	0,
            'src'           =>  self::$src
		];

		$info = self::updateTokenCache($token, $updateTokenInfo);
		if ($info['code'] === RETURN_SUCCESS) {
            if (env("APP_ENV") !== "testing") {
                $updateTokenInfo['token'] = $newTokenInfo['cryptToken'];
            } else {
                $updateTokenInfo['cryptToken'] = $newTokenInfo['cryptToken'];
            }
			HandleLog()->addLog('u', $updateTokenInfo, '更新了token');
			return ModelReturn(RETURN_SUCCESS, '更新TOKEN成功', $updateTokenInfo);
		}
		return $info;
	}

    /**
     * 更新token信息
     * @param $token 用户TOKEN
     * @param array $updateData 更新的数据
     * @param bool $isUpdateDb 是否强制刷新到DB
     * @return array|array
     * @throws \Exception
     */
	public static function updateTokenCache($token, $updateData = [], $isUpdateDb = true)
	{
		$userInfo = self::getUserInfo($token);
		if ($userInfo['code'] != RETURN_SUCCESS) {
			return $userInfo;
		}

		$userObj = $userInfo['data'];
		$tokenInfo = $userObj['tokenInfo'];
		foreach ($updateData as $key => $value) {
			isset($tokenInfo[$key]) && $tokenInfo[$key] = $value;
		}
		$tokenInfo['update_time'] = time();
		$userObj['tokenInfo'] = $tokenInfo;
		$cacheToken = self::$cachePrefix . $token;
		if (!DB::table('sc_token_cache')->whereRaw("token=? AND src=?", [$token, self::$src])->first()) {
			return ModelReturn(RETURN_FAIL, "更新Token缓存信息失败");
		}

		try {
			Cache::put($cacheToken, $userObj, self::$expireTime);
			$isUpdateDb && DB::table('sc_token_cache')->whereRaw("token=? AND src=?", [$token, self::$src])->update($userObj['tokenInfo']);
			return ModelReturn(RETURN_SUCCESS, '更新成功', $userObj);
		} catch (\Throwable $e) {
			self::LoginOut($token);
			if (config('app.debug')) {
				return ModelReturn($e->getCode(), $e->getMessage());
			} else {
				return ModelReturn($e->getCode(), "更新Token缓存信息失败");
			}
		}
	}

    /**
     * 退出登录
     * @param $token 用户TOKEN
     * @return array
     * @throws \Exception
     */
	public static function LoginOut($token)
	{
		$cacheToken = self::$cachePrefix . $token;
		Cache::forget($cacheToken);
		DB::table('sc_token_cache')->whereRaw("token=? AND src=?", [$token, self::$src])->update([
			'is_invalid'	=>	1,
			'update_time'	=>	time()
		]);
		HandleLog()->addLog('d', ['token' => $token], '退出了系统');
		return ModelReturn(RETURN_SUCCESS, '退出登录成功');
	}

    /**
     * 用户注册
     * @param $userName 用户名
     * @param $userPwd 用户密码
     * @return array
     */
	public static function register($userName, $userPwd) {
        $userObj = DB::table('sc_user')->where("username", $userName)->first();
        if ($userObj) {
            return ModelReturn(RETURN_CHECK_DATA_DB_FAIL, '该登录账户已存在,请修改登录账户进行注册');
        }
        $checkPassword =self::createCheckPassword($userPwd)['data'];
        $insertData = [
            'nike_name' =>  substr($userName, 0, 10),
            'username'  =>  $userName,
            'password'  =>  $checkPassword,
            'is_supper_admin'   =>  0
        ];
        try {
            DB::beginTransaction();
            DB::table('sc_user')->insert($insertData);
            HandleLog()->addLog('i', $insertData, "用户{$userName}注册了账号");
            DB::commit();
            return ModelReturn(RETURN_SUCCESS, '注册成功');
        } catch (\Exception $e) {
            DB::rollBack();
            return ModelReturn($e->getCode(), '注册失败:' . $e->getMessage());
        }
    }

    /**
     * 修改用户密码
     * @param $token
     * @param $oldPwd
     * @param $newPwd
     * @return array
     */
    public static function updatePwd($token, $oldPwd, $newPwd) {
        $userObj = self::getUserInfo($token, 'id');
        if ($userObj['code'] != RETURN_SUCCESS) {
            return $userObj;
        }
        $userId = $userObj['data'];
        $checkPassword = self::createCheckPassword($oldPwd)['data'];
        $userExit = DB::table('sc_user')->whereRaw("id=? AND password=?", [$userId, $checkPassword])->first();
        if (!$userExit) {
            return ModelReturn(RETURN_CHECK_DATA_DB_FAIL, '用户原始密码错误');
        }

        $newUserPwd = self::createCheckPassword($newPwd)['data'];
        try {
            DB::table('sc_user')->where('id', $userId)->update([
                'is_update_init_pwd'    =>  1,
                'password'              =>  $newUserPwd
            ]);
            HandleLog()->addLog("u", ['userId'=>$userId], '修改了账户密码');
            return ModelReturn(RETURN_SUCCESS, '修改成功');
        } catch (\Throwable $exception) {
            return ModelReturn($exception->getCode(), $exception->getMessage());
        }
    }

    /**
     * 重置用户密码
     * @param $token
     * @param $newPwd
     * @return array
     */
    public static function resetUserPwd($token, $newPwd) {
        $userObj = self::getUserInfo($token);
        if ($userObj['code'] != RETURN_SUCCESS) {
            return $userObj;
        }
        $isAdmin = $userObj['data']['is_supper_admin'] == 0 ? false : true;

        if (!$isAdmin) {
            return ModelReturn(RETURN_CHECK_DATA_DB_FAIL, '无权限进行密码重置,请联系超级管理员进行重置');
        }
        $userId = $userObj['data']['id'];
        $newUserPwd = self::createCheckPassword($newPwd)['data'];
        try {
            DB::table('sc_user')->where('id', $userId)->update([
                'is_update_init_pwd'    =>  1,
                'password'              =>  $newUserPwd
            ]);
            HandleLog()->addLog("u", ['userId'=>$userId], '重置了账户密码');
            return ModelReturn(RETURN_SUCCESS, '修改成功');
        } catch (\Throwable $exception) {
            return ModelReturn($exception->getCode(), $exception->getMessage());
        }
    }
}
